Skip to content

✨ Add fuse-two-qubit-unitary-runs pass#1865

Open
simon1hofmann wants to merge 33 commits into
mainfrom
feat/fuse-two-qubit-unitary-runs
Open

✨ Add fuse-two-qubit-unitary-runs pass#1865
simon1hofmann wants to merge 33 commits into
mainfrom
feat/fuse-two-qubit-unitary-runs

Conversation

@simon1hofmann

@simon1hofmann simon1hofmann commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Add a fuse-two-qubit-unitary-runs MLIR pass that fuses compile-time two-qubit unitary windows and resynthesizes them to a native gateset via Weyl/KAK decomposition.

AI Assistance

Used Composer 2.5 via Cursor for parts of this change. I reviewed the full
diff and take responsibility for everything in this PR.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • AI-assisted commits include an Assisted-by: [Model Name] via [Tool Name] footer.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

simon1hofmann and others added 3 commits July 7, 2026 10:02
Add a `fuse-two-qubit-unitary-runs` MLIR pass that fuses compile-time
two-qubit unitary windows and resynthesizes them to a native gateset via
Weyl/KAK decomposition. Includes the pass definition, implementation,
unit tests, and CMake wiring.

Also add the `isEquivalentUpToGlobalPhase` matrix helper used by the new
tests to compare unitaries up to a global phase.

Assisted-by: Claude Opus 4.8 via Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
@simon1hofmann simon1hofmann changed the title ✨ Add fuse-two-qubit-unitary-runs pass ✨ Add fuse-two-qubit-unitary-runs pass Jul 7, 2026
@simon1hofmann simon1hofmann self-assigned this Jul 7, 2026
@simon1hofmann simon1hofmann added enhancement Improvement of existing feature c++ Anything related to C++ code MLIR Anything related to MLIR labels Jul 7, 2026
@simon1hofmann simon1hofmann added this to the MLIR Support milestone Jul 7, 2026
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.33198% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...sforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp 92.9% 14 Missing ⚠️

📢 Thoughts on this report? Let us know!

@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a1af00c0-3a45-46f1-8bd3-5aa301a74b27

📥 Commits

Reviewing files that changed from the base of the PR and between 1c61737 and 7b2cd01.

📒 Files selected for processing (1)
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added fuse-two-qubit-unitary-runs pass to fuse two-qubit unitary runs and lower eligible operations to a chosen native-gates menu.
    • Added native-gates / --native-gates support in mqt-cc.
    • Exposed QCOProgram.fuse_two_qubit_unitary_runs(native_gates=...) in C++ and Python.
  • Bug Fixes
    • Improved handling of controlled bodies and added stronger validation/erroring when unsupported unitary shells remain.
  • Tests
    • Added unit tests for correctness, native-menu parsing/validation (including no-op on empty menus), edge cases, and determinism.

Walkthrough

Adds an MLIR QCO pass that fuses two-qubit unitary runs, resynthesizes them to a native gateset, and validates the result. Compiler, CLI, and Python APIs, reusable single-qubit fusion wiring, tests, and changelog entries are also added.

Changes

Two-Qubit Unitary Fusion Pass

Layer / File(s) Summary
Native gateset and single-qubit fusion contracts
mlir/include/.../Decomposition/*, mlir/lib/.../NativeGateset.cpp, mlir/lib/.../FuseSingleQubitUnitaryRuns.cpp, mlir/unittests/.../test_weyl_decomposition.cpp
Adds operation eligibility checks and reusable single-qubit fusion patterns that can skip controlled bodies.
Pass definition and two-qubit synthesis
mlir/include/.../Passes.td, mlir/lib/.../FuseTwoQubitUnitaryRuns.cpp
Defines the pass and implements run scanning, Weyl resynthesis, off-gateset lowering, orchestration, and convergence validation.
Compiler, CLI, and Python integration
mlir/include/mlir/Compiler/Programs.h, mlir/lib/Compiler/Programs.cpp, mlir/tools/mqt-cc/mqt-cc.cpp, bindings/mlir/register_mlir.cpp, python/mqt/core/mlir.pyi
Registers the pass and exposes two-qubit fusion through compiler, command-line, and Python APIs.
Fusion test coverage and build wiring
mlir/unittests/Dialect/QCO/Transforms/..., mlir/unittests/Compiler/test_compiler_pipeline.cpp
Adds native-compliance, equivalence, boundary, failure, determinism, API, and build coverage.
Changelog update
CHANGELOG.md
Adds the unreleased pass entry and PR reference.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: feature

Suggested reviewers: burgholzer

Poem

I hopped through qubits, two by two,
And shaped their runs in native hue.
Weyl sang softly, gates aligned,
While tests kept every phase in mind.
🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly names the main change: adding the fuse-two-qubit-unitary-runs pass.
Description check ✅ Passed The description includes a summary, AI assistance disclosure, and checklist items aligned with the template; missing issue/dependency details are non-critical.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/fuse-two-qubit-unitary-runs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mlir/include/mlir/Dialect/QCO/Transforms/Passes.td`:
- Around line 88-89: The gate-set docs in Passes.td are advertising the
unsupported `p` alias even though `parseGateToken` only recognizes `rz`, so
update the `QCO` pass descriptions to match the parser by either adding `p`
handling in `parseGateToken` or removing `p` from the documented token list and
any related examples/comments. Make sure the wording around the gate tokens in
the pass definitions stays consistent with the actual accepted syntax.

In `@mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp`:
- Around line 248-250: The comparison in the `FuseTwoQubitUnitaryRuns` scan is
unsafe because `uniqueUnitaryUser()` does not guarantee `nextOnA` and `nextOnB`
are in the same block, so `isBeforeInBlock` can trip MLIR preconditions when the
run spans blocks or regions. Update the logic around the `aSingle`/`bSingle`
check to first verify both successors are in the same block, and if not, stop
the scan before calling `isBeforeInBlock`; use the existing `nextOnA`,
`nextOnB`, and `sameOp` flow in `FuseTwoQubitUnitaryRuns.cpp` to place this
guard.

In `@mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/CMakeLists.txt`:
- Around line 12-26: The NativeSynthesis test target is missing the MemRef
dialect dependency even though the test registers memref::MemRefDialect in the
related test source. Update the target_link_libraries list for the test target
to include MLIRMemRefDialect alongside the existing MLIR dialect libraries,
matching the pattern used by other QCO test targets such as test_qc_ir.cpp and
test_qc_to_qco.cpp.

In
`@mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp`:
- Around line 388-390: The boundary comment in the test is stale and contradicts
the current pass behavior: in the scenario around the entangler and the
three-qubit gate, the wider gate should be described as stopping the run scan
and being left untouched, not “for the pass to reject.” Update the comment near
the affected test case in test_fuse_two_qubit_unitary_runs.cpp so it matches the
contract exercised by the surrounding test and the NativeSynthesis pass
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dbd760f5-f291-4778-bbd7-825ed27db900

📥 Commits

Reviewing files that changed from the base of the PR and between 5a1ea9d and 0b7922d.

📒 Files selected for processing (11)
  • CHANGELOG.md
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/Euler.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/NativeGateset.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/NativeGateset.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseSingleQubitUnitaryRuns.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp
  • mlir/unittests/Dialect/QCO/Transforms/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp

Comment thread mlir/include/mlir/Dialect/QCO/Transforms/Passes.td Outdated
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@mergify mergify Bot added the conflict label Jul 8, 2026
@simon1hofmann
simon1hofmann marked this pull request as ready for review July 13, 2026 12:29
@simon1hofmann
simon1hofmann requested a review from burgholzer July 13, 2026 12:29
@mergify mergify Bot added the conflict label Jul 13, 2026
Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com>
@mergify mergify Bot removed the conflict label Jul 15, 2026
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp (1)

349-354: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Prevent compiler crash by verifying the operation is a two-qubit gate.

LowerTwoQubitOpPattern matches any UnitaryOpInterface. If an off-gateset single-qubit gate (e.g., one with an unknown/dynamic matrix that couldn't be fused) or a >2-qubit gate reaches this pattern, spec.allowsOp(raw) will evaluate to false. The operation will then be passed to assignTwoQubitOpMatrix. Since it is not a CtrlOp, assignTwoQubitOpMatrix will trigger its internal assertion (assert(unitary.isTwoQubit() ...)) and crash the compiler.

Add a guard to ensure only two-qubit operations are processed by this lowering pattern.

🛡️ Proposed fix
   LogicalResult matchAndRewrite(UnitaryOpInterface op,
                                 PatternRewriter& rewriter) const override {
+    if (!op.isTwoQubit()) {
+      return failure();
+    }
     Operation* raw = op.getOperation();
     if (!isWalkableUnitaryShell(raw) || spec.allowsOp(raw)) {
       return failure();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp`
around lines 349 - 354, Update LowerTwoQubitOpPattern::matchAndRewrite to reject
operations unless op represents exactly a two-qubit unitary before calling
assignTwoQubitOpMatrix. Keep the existing isWalkableUnitaryShell and
spec.allowsOp checks, and return failure for single-qubit or
greater-than-two-qubit operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp`:
- Around line 349-354: Update LowerTwoQubitOpPattern::matchAndRewrite to reject
operations unless op represents exactly a two-qubit unitary before calling
assignTwoQubitOpMatrix. Keep the existing isWalkableUnitaryShell and
spec.allowsOp checks, and return failure for single-qubit or
greater-than-two-qubit operations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc6413a9-c136-4b15-b30a-b93f897dfc36

📥 Commits

Reviewing files that changed from the base of the PR and between c4e0969 and 1c61737.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • bindings/mlir/register_mlir.cpp
  • mlir/include/mlir/Compiler/Programs.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
  • mlir/lib/Compiler/Programs.cpp
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/NativeGateset.cpp
  • mlir/lib/Dialect/QCO/Transforms/NativeSynthesis/FuseTwoQubitUnitaryRuns.cpp
  • mlir/lib/Support/Passes.cpp
  • mlir/tools/mqt-cc/mqt-cc.cpp
  • mlir/unittests/Compiler/test_compiler_pipeline.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_weyl_decomposition.cpp
  • mlir/unittests/Dialect/QCO/Transforms/NativeSynthesis/test_fuse_two_qubit_unitary_runs.cpp
  • python/mqt/core/mlir.pyi

@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@mergify mergify Bot added the conflict label Jul 22, 2026
Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com>
@mergify mergify Bot added conflict and removed conflict labels Jul 22, 2026
simon1hofmann and others added 3 commits July 23, 2026 09:43
Co-authored-by: Cursor <cursoragent@cursor.com>
Assisted-by: Cursor Grok 4.5 via Cursor
@mergify mergify Bot added conflict and removed conflict labels Jul 23, 2026
@mergify mergify Bot removed the conflict label Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code enhancement Improvement of existing feature MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant